﻿using System.Collections.Generic;
using ClientOverflow.DataTransferObjects;
using ClientOverflow.ViewModels.Interfaces;
using ClientOverflow.ViewModels.MainMenus;
using ClientOverflow.ViewModels.QuestionsListViewModels;
using DynamicControllersGeneration;
using System.Linq;

namespace ClientOverflow.ViewModels.UserProfileViewModels
{
    /// <summary>
    /// UserProfileViewModel is a view model that wraps a user as an underlying model. This view-model
    /// exposes extended details about the user. It shows the user personal information, summary of the
    /// user questions, answers and tags. This view-model is an abstract class instantiated in runtime
    /// using a dynamic proxy. The proxy is in charge of routing calls to the model (which are the user,
    /// the questions and the answers related to the user).
    /// </summary>
    public abstract class UserProfileViewModel : IUserProfileViewModel
    {
        private static readonly ViewModelGenerator viewModelGenerator = new ViewModelGenerator();

        internal static IUserProfileViewModel CreateUserProfileViewModel(User user, IMenusViewModel viewModel)
        {
            return viewModelGenerator.Generate<UserProfileViewModel>(user, viewModel);
        }

        protected UserProfileViewModel([Model]User user, IMenusViewModel viewModel)
        {
            UpdateAnswersQuestion(user);
            InitializeQuestions(user, viewModel);
            InitializeAnswers(user, viewModel);
            InitializeTags(user, viewModel);
        }

        private void InitializeAnswers(User user, IMenusViewModel viewModel)
        {
            Answers = user.Answers
                .Select(answer => AnswerViewModel.CreateAnswerViewModel(answer, viewModel))
                .ToList();
        }

        private void InitializeTags(User user, IMenusViewModel viewModel)
        {
            var userQuestionsFilter = new UserQuestionsFilter(user);
            
            IEnumerable<IGrouping<Tag, Tag>> groupBy = user.Questions.SelectMany(question => question.Tags)
                .Concat(user.Answers.SelectMany(answer => answer.Question.Tags))
                .GroupBy(tag => tag);
            Tags = groupBy.Select(tags => TagViewModel.CreateTagViewModel(tags.Key, tags.Count(), viewModel, new CompositeQuestionsFilter(new IQuestionsFilter[]{userQuestionsFilter, new TagQuestionsFilter(tags.Key)})))
                .ToList();
        }

        private void InitializeQuestions(User user, IMenusViewModel viewModel)
        {
            Questions = user.Questions
                .Select(question => QuestionViewModel.CreateQuestionViewModel(question, viewModel))
                .ToList();
        }

        private static void UpdateAnswersQuestion(User user)
        {
            using (var serviceClient = ServicesFactory.CreateClientOverflowServiceClient())
            {
                user.Answers.ForEach(answer => answer.Question = serviceClient.GetQuestion(answer));
            }
        }

        public abstract string Name { get; }
        public abstract string Email { get; }

        public IList<IQuestionInListViewModel> Questions { get; private set; }
        public IList<IAnswerInListViewModel> Answers { get; private set; }
        public IList<ITagViewModel> Tags { get; private set; }
    }
}